/+
Library dbapi - Simple database api for the D programming language.

Copyright (C) 2007 Myron Alexander (myron.alexander...gmail.com)

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+/

module dbapi.internal.util;

import std.string : str = toString, find;
import std.outofmemory : _d_OutOfMemory;
import stdlib = std.c.stdlib : malloc, free;

/**
 * Create a WeakReference to an Object such that the GC will not be prevented
 * from collecting the referenced object.
 *
 * Thanks to Bill Baxter for pointing me in the right direction.
 */
class WeakObjectReference(T : Object) {

   this (T obj) {
      /* Get a pointer to the object referenced. The pointer is necessary as
       * I do not what type to declare a pointer to a reference (ie T*->T).
       * I tried T*T but that doesn't work. The T** implementation works but
       * out of curiosity, it would be nice to know if something like T*T could
       * be done.
       */
      T* p = cast(T*)obj;

      /* Allocate a non-gc region of memory to store the pointer to the object.
       * The type is T** as it is: memptr -> T* -> obj.
       */
      weakObjRef = cast(T**)stdlib.malloc (p.sizeof);

      if (null == weakObjRef) {
         _d_OutOfMemory ();
      }

      /* Set memptr->T* = address of obj reference.
       */
      *weakObjRef = p;

      /* Request that the GC call the unhook delegate when the referenced object
       * is collected. The unhook delegate removes the pointer to the object.
       * This is very important otherwise we would maintain a pointer to a
       * non-existant object.
       */
      obj.notifyRegister (&unhook);
   }

   ~this () {
      /* Remove the object destruction notification delegate as we will no
       * longer maintain a link to that object.
       */
      if (*weakObjRef != null) {
         (cast(T)(*weakObjRef)).notifyUnRegister (&unhook);
         *weakObjRef = null;
      }

      /* Free the non-gc memory allocated in the constructor.
       */
      stdlib.free (weakObjRef);
   }

   T get () {
      return cast(T)(*weakObjRef);
   }

   private void unhook (Object obj) {
      *weakObjRef = null;
   }

   private T** weakObjRef;
}

/**
 * Find a substring within a string searching from the given index.
 */
int find (int start, string s, string sub) {

   int idx = find (s[start..$], sub);

   if (-1 == idx) {
      return -1;

   } else {
      return start + idx;
   }
}
